package com.qm.console.service.user.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.qm.console.component.exception.BusinessException;
import com.qm.console.component.util.BeanUtil;
import com.qm.console.component.util.HttpInvokeUtil;
import com.qm.console.controller.dto.ResultEnum;
import com.qm.console.dao.mapper.AccountRegisterDOMapper;
import com.qm.console.dao.mapper.UserMessageDOMapper;
import com.qm.console.dao.model.UserMessageDO;
import com.qm.console.pubdef.constant.UrlConstant;
import com.qm.console.pubdef.constant.UserMessageState;
import com.qm.console.pubdef.dto.user.UserMessageDTO;
import com.qm.console.pubdef.dto.user.UserMessageQueryDTO;
import com.qm.console.service.user.UserMessageService;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;

import lombok.extern.slf4j.Slf4j;
import redis.clients.jedis.BinaryClient;

/**
 * //                       _oo0oo_
 * //                      o8888888o
 * //                      88" . "88
 * //                      (| -_- |)
 * //                      0\  =  /0
 * //                    ___/`---'\___
 * //                  .' \\|     |// '.
 * //                 / \\|||  :  |||// \
 * //                / _||||| -:- |||||- \
 * //               |   | \\\  -  /// |   |
 * //               | \_|  ''\---/''  |_/ |
 * //               \  .-\__  '-'  ___/-. /
 * //             ___'. .'  /--.--\  `. .'___
 * //          ."" '<  `.___\_<|>_/___.' >' "".
 * //         | | :  `- \`.;`\ _ /`;.`/ - ` : | |
 * //         \  \ `_.   \_ __\ /__ _/   .-` /  /
 * //     =====`-.____`.___ \_____/___.-`___.-'=====
 * //                       `=---='
 * //
 * //
 * //     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 * //
 * //               佛祖保佑         永无BUG
 * <p>
 * com.qm.console.service.user.impl
 * Created on 2020/11/18.
 */
@Service
@Slf4j
public class UserMessageServiceImpl implements UserMessageService {

    @Autowired
    private UserMessageDOMapper userMessageDOMapper;
    @Autowired
    private AccountRegisterDOMapper accountRegisterDOMapper;

    @Override
    public void createMessage(UserMessageDTO userMessageDTO) {
        List<Integer> uids = userMessageDTO.getUids();
        if (uids == null || uids.isEmpty()) {
            return;
        }
        List<Integer> validUids = accountRegisterDOMapper.checkUids(uids);

        uids.forEach(uid -> {
            UserMessageDO item = new UserMessageDO();
            BeanUtils.copyProperties(userMessageDTO, item);
            if (validUids.contains(uid)) {
                item.setState(UserMessageState.STATE_WAITING);
            } else {
                item.setState(UserMessageState.STATE_INVALID);
            }
            item.setTargetUserId(uid);
            userMessageDOMapper.insertSelective(item);
        });
    }

    @Override
    public void deleteMessage(List<Integer> ids) {
        List<UserMessageDO> items = userMessageDOMapper.listByIds(ids);
        items.forEach(item -> {
            if (item.getState() == UserMessageState.STATE_OK || item.getState() == UserMessageState.STATE_SENDING) {
                throw new BusinessException(ResultEnum.USER_MESSAGE_DEL_ERROR_ALREADY_SENT, item.getId());
            }
        });
        ids.forEach(id -> {
            userMessageDOMapper.deleteByPrimaryKey(id);
        });
    }

    @Override
    public void updateMessage(UserMessageDO userMessageDO) {
        if (userMessageDO.getId() == null) {
            throw new BusinessException(ResultEnum.USER_MESSAGE_FAILED_TO_FIND);
        }
        UserMessageDO cur = userMessageDOMapper.selectByPrimaryKey(userMessageDO.getId());
        if (userMessageDO.getId() == null) {
            throw new BusinessException(ResultEnum.USER_MESSAGE_FAILED_TO_FIND);
        }
        if (cur.getState() == UserMessageState.STATE_OK || cur.getState() == UserMessageState.STATE_SENDING) {
            throw new BusinessException(ResultEnum.USER_MESSAGE_UPDATE_ERROR, cur.getId());
        }
        userMessageDO.setState(null);
        userMessageDO.setRetry(null);
        userMessageDOMapper.updateByPrimaryKeySelective(userMessageDO);
    }

    @Override
    public List<UserMessageDO> getMessages(UserMessageQueryDTO queryDTO) {
        return userMessageDOMapper.list(queryDTO);
    }

    @Override
    public Integer getMessageCount(UserMessageQueryDTO queryDTO) {
        return userMessageDOMapper.count(queryDTO);
    }

    @Override
    public void pushMessage(List<Integer> ids) {
        userMessageDOMapper.setPushStateInQueue(ids);
        BeanUtil.getApplicationContext().publishEvent(new NeedPushEvent());
    }

    private static boolean PUSH_STARTED = false;

    @Async
    @EventListener
    @Override
    public void onPushEvent(NeedPushEvent event) {
        if (PUSH_STARTED) {
            return;
        }
        PUSH_STARTED = true;
        try {
            UserMessageDO next = userMessageDOMapper.nextMessage();
            while (next != null) {
                pushMessageImpl(next);
                next = userMessageDOMapper.nextMessage();
            }
        } catch (Exception e) {
        }
        PUSH_STARTED = false;
    }

    private void pushMessageImpl(UserMessageDO messageDO) {
        String url= UrlConstant.ApiServerHost;
        url = url.replace("admin", "app");
        url += "/im/console/msg";

        String result = HttpInvokeUtil.httpPostJson(url, JSON.toJSONString(messageDO), "utf8", null);
        JSONObject json = JSON.parseObject(result);
        log.info("push message {}, result: {}", messageDO, result);
        if (StringUtils.equals(json.getString("message"), "SUCCESS") || StringUtils.equals(json.getString("message"), "ok")) {
            userMessageDOMapper.setPushResult(messageDO.getId(), UserMessageState.STATE_OK);
        } else {
            userMessageDOMapper.setPushResult(messageDO.getId(), UserMessageState.STATE_FAILED);
        }

    }


}
